#ifndef Simple_State_Machine_STATE_included
#define Simple_State_Machine_STATE_included

#include <assert.h>

#define UNUSED_PARAMETER(expr) do { (void)(expr); } while (0)

namespace SimpleStateMachineLib
{

template <class TStateMachine>
class State
{
    TStateMachine* m_pContext;

public:
    typedef typename TStateMachine::EventType EventType;

    void setStateMachine(TStateMachine* pMachine)
    {
        m_pContext = pMachine;
    }
 
    TStateMachine* machine()
    {
        return m_pContext;
    }

    void transition(State& state)
    {
        m_pContext->transition(state);
    }

    virtual void onEntry()
    {
    }

    virtual void onExit()
    {
    }

    virtual bool handleEvent(const EventType&)
    {
        return false;
    }

    virtual const char* toString() const
    {
        return "State";
    }

};


template <class TSubClass, class TEvent>
class StateMachine
{
public:
    typedef State<TSubClass> StateType;
    typedef TEvent EventType;

private:
    StateType* m_pCurrentState;
    StateType* m_pInitialState;

public:

	StateMachine()
        : m_pCurrentState(0),
        m_pInitialState(0)
    {
    }

    void setInitialState(StateType& state)
    {
        m_pInitialState = &state;
    }


    void transition(StateType& state)
    {
        m_pCurrentState = &state;
    }


    void onEntry()
    {
    	assert(m_pInitialState != 0
    			&& "setInitialState must be called before onEntry");
        m_pCurrentState=m_pInitialState;
        m_pCurrentState->onEntry();
    }

    void onExit()
    {
        m_pCurrentState->onExit();
        m_pCurrentState = 0;
    }


    bool handleEvent(const EventType& event)
    {
        StateType* previousState = m_pCurrentState;
        m_pCurrentState = 0;
        previousState->handleEvent(event);
        if(m_pCurrentState != 0)
        {
            static_cast<TSubClass*>(this)->onTransition(
                event, *previousState, *m_pCurrentState);

            previousState->onExit();
            m_pCurrentState->onEntry();
        }
        else
        {
            m_pCurrentState = previousState;
        }
        return true;
    }
protected:
    void onTransition(const EventType& event,
        const StateType& fromState, 
        const StateType& toState)
    {
        UNUSED_PARAMETER(event);
        UNUSED_PARAMETER(fromState);
        UNUSED_PARAMETER(toState);
    }
};


template <typename TInnerStateMachine, typename TBaseState>
class CompositeState: public TBaseState
{
	TInnerStateMachine m_inner;

public:
	typedef typename TBaseState::EventType EventType;
	typedef CompositeState BaseType;

	void onEntry()
	{
		m_inner.onEntry();
	}

	void onExit()
	{
		m_inner.onExit();
	}

	bool handleEvent(const EventType& ev)
	{
		return m_inner.handleEvent(ev);
	}

	TInnerStateMachine& getInner()
	{
		return m_inner;
	}
};


}

#endif
